﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using GUI.Custom_Classes;
using System.ComponentModel;
using WinForms = System.Windows.Forms;
using Tedds_Tool;
using Ins = Tedds_Tool.Instructions;
using System.IO;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.Media;
using System.Windows.Automation;
using Compiled_Tests.Utils;
using System.Threading;
using System.Collections.ObjectModel;
using Tedds_Tool.Compilers.LEET;
using System.Management;

namespace GUI.Tabs
{
    /// <summary>
    /// Interaction logic for MainTab.xaml
    /// </summary>
    public partial class MainTab : UserControl
    {
        #region Attributes

        /// <summary>
        /// Controller that manages the main script functionality and user interaction
        /// </summary>
        ScriptController scriptController;

        /// <summary>
        /// Controller that manages drag and drop of individual script items
        /// </summary>
        DragAndDropController dragAndDrop;

        /// <summary>
        /// Controller that manages recording functionality
        /// </summary>
        RecordingController recordingController;

        /// <summary>
        /// Main controller for GUI to control set of advanced features
        /// </summary>
        private GuiController mainControl;

        public IScriptFinder ScriptFinder { get; private set; }
        private double previousOffset = 0;
        private ISettings settings;
        public LEETCompilerFactory cFac { get; set; }
        private Tedds_Tool.Automatables.ILEETFactory _Factory;
        bool previouslyInited = false;
        private double scrolloffset = 0;

        
        
        #endregion

        public MainTab()
        {
            InitializeComponent();
            Script_Viewer.LineNumbers = ScriptViewerLineNums;
            Script_Viewer.KeyDown += new KeyEventHandler(DeleteKeyPressed);
            mainControl = new GuiController(Script_Viewer);
        }

        public void init(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (cFac != null)
            {
                if (scriptController != null)
                {
                    Startup_and_Record.Click -= scriptController.RefreshErrorLine;
                    Window_Selector.Click -= scriptController.RefreshErrorLine;
                    Add_Button.Click -= scriptController.RefreshErrorLine;
                    Remove_Button.Click -= scriptController.RefreshErrorLine;
                    Compile_Demo_Button.Click -= scriptController.CompileDemo;
                    Run_Demo_Button.Click -= scriptController.RunDemo;
                    Run_Demo_Button.Click -= mainControl.StartWatcher;
                    Compile_Test_Button.Click -= scriptController.CompileTest;
                    Run_Test_Button.Click -= scriptController.RunTest;
                    Run_Test_Button.Click -= mainControl.StartWatcher;
                    Load_Script_Button.Click -= scriptController.Clear;
                    Load_Script_Button.Click -= scriptController.Load;
                    Save_Script_Button.Click -= scriptController.Save;
                    Clear_Script_Button.Click -= scriptController.Clear;
                }
                
                scriptController = new ScriptController(Script_Viewer, new Facade(cFac.CreateCompiler(), new CS_Compiler(settings.TestDLL.FullName), Factory, ScriptFinder), ScriptFinder);

                Startup_and_Record.Click += scriptController.RefreshErrorLine;
                Window_Selector.Click += scriptController.RefreshErrorLine;
                Add_Button.Click += scriptController.RefreshErrorLine;
                Remove_Button.Click += scriptController.RefreshErrorLine;
                Compile_Demo_Button.Click += scriptController.CompileDemo;
                Run_Demo_Button.Click += scriptController.RunDemo;
                Run_Demo_Button.Click += mainControl.StartWatcher;
                Compile_Test_Button.Click += scriptController.CompileTest;
                Run_Test_Button.Click += scriptController.RunTest;
                Run_Test_Button.Click += mainControl.StartWatcher;
                Load_Script_Button.Click += scriptController.Clear;
                Load_Script_Button.Click += scriptController.Load;
                Save_Script_Button.Click += scriptController.Save;
                Clear_Script_Button.Click += scriptController.Clear;

                if (dragAndDrop != null)
                {
                    Script_Viewer.PreviewMouseDown -= dragAndDrop.ScriptViewerMouseDown;
                    Script_Viewer.PreviewMouseUp -= dragAndDrop.ScriptViewerMouseUp;
                }

                dragAndDrop = new DragAndDropController(Script_Viewer);
                Script_Viewer.PreviewMouseDown += dragAndDrop.ScriptViewerMouseDown;
                Script_Viewer.PreviewMouseUp += dragAndDrop.ScriptViewerMouseUp;

                if (recordingController != null)
                {
                    Startup_and_Record.Click -= recordingController.Startup_and_Record_Click;
                    Record_Button.Click -= recordingController.Record_Button_Click;
                    Window_Selector.Click -= recordingController.Window_Selector_Click;
                    Add_Button.Click -= recordingController.Add_Button_Click;
                    Remove_Button.Click -= recordingController.Remove_Button_Click;
                }
                
                recordingController = new RecordingController
                    (Factory, Script_Viewer, new MessageBoxAlerts(App.Current.MainWindow), 
                    ScriptFinder, new SetText(Current_Target_Info), Window_Selector, Record_Button);

                Startup_and_Record.Click += recordingController.Startup_and_Record_Click;
                Record_Button.Click += recordingController.Record_Button_Click;
                Window_Selector.Click += recordingController.Window_Selector_Click;
                Add_Button.Click += recordingController.Add_Button_Click;
                Remove_Button.Click += recordingController.Remove_Button_Click;

                if (previouslyInited)
                {
                    CreatePrecond_Button.Click -= CreatePrecond_Click;
                    CreateAction_Button.Click -= CreateAction_Click;
                    //CreateCons_Button.Click -= CreateCons_Click;
                }

                CreatePrecond_Button.Click += CreatePrecond_Click;
                CreateAction_Button.Click += CreateAction_Click;
                //CreateCons_Button.Click += CreateCons_Click;
                
                previouslyInited = true;
            }
        }

        #region Rule Creator UIs

        public void CreatePrecond_Click(object sender, RoutedEventArgs e)
        {
            CreatePrecond pre = new CreatePrecond(Factory, Script_Viewer, ScriptFinder);
            pre.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
            FrameworkElement parent = this;
            while (parent != null && !(parent is Window))
                parent = parent.Parent as FrameworkElement;
            if (parent is Window)
                pre.Owner = parent as Window;
            pre.Show();
        }

        public void CreateAction_Click(object sender, RoutedEventArgs e)
        {
            CreateAction act = new CreateAction(Factory, Script_Viewer, ScriptFinder);
            act.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
            FrameworkElement parent = this;
            while (parent != null && !(parent is Window)) 
                parent = parent.Parent as FrameworkElement;
            if(parent is Window)
                act.Owner = parent as Window;
            act.Show();
        }

        public void CreateCons_Click(object sender, RoutedEventArgs e)
        {
            //CreateCons cons = new CreateCons(Factory, ScriptFinder);
            //cons.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
            //cons.Show();
        }

        #endregion

        #region Helper Functions

        public void OnSettingsChange(ISettings settings)
        {
            this.settings = settings;
            ScriptFinder = new ScriptFinder(settings);
            if (settings.TestDLL != null)
            {
                cFac = new LEETCompilerFactory(Factory);
            }
            init(null, default(DependencyPropertyChangedEventArgs));
        }

        internal void TT_GUI_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if(recordingController != null) recordingController.ShutDown();
            if (Application.Current != null) Application.Current.Shutdown();
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Captures scroll bar movement to keep viewing panes synchronized.
        /// </summary>
        private void Script_Viewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.Source.GetType().Equals(typeof(ComboBox))) //This ignores ScriptBuilder dropdown events
                return;

            if (sender == Script_Viewer.Parent)
            {
                if (previousOffset == e.VerticalOffset)
                    return;

                scrolloffset = previousOffset;
                previousOffset = e.VerticalOffset;
                ((ScrollViewer)Script_Viewer.Parent).ScrollToVerticalOffset(previousOffset);
                ScrollTo(ScriptViewerLineNums, previousOffset);
            }
            if (sender == ScriptViewerLineNums)
                ScrollTo(ScriptViewerLineNums, previousOffset);
        }

        /// <summary>
        /// Finds the embedded scroll object to scroll to a vertical offset.
        /// </summary>
        /// <param name="n">The root element to begin looking from.</param>
        /// <param name="offset">The value of the vertical scrollbar offset.</param>
        private static void ScrollTo(DependencyObject n, double offset)
        {
            // Return the DependencyObject if it is a ScrollViewer
            bool terminate = false;
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(n); i++)
            {
                var child = VisualTreeHelper.GetChild(n, i);
                if (child is ScrollViewer)
                {
                    (child as ScrollViewer).ScrollToVerticalOffset(offset);
                    terminate = true;
                }
            }
            if (!terminate)
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(n); i++)
                    ScrollTo(VisualTreeHelper.GetChild(n, i), offset);
        }

        #endregion

        internal void CheckedIfSaveNeeded(object sender, CancelEventArgs e)
        {
            if (Script_Viewer.scriptchanged)
                scriptController.Save(null, null);
        }

        public Tedds_Tool.Automatables.ILEETFactory Factory
        {
            get
            {
                return _Factory;
            }
            set
            {
                _Factory = value;
                Script_Viewer.Factory = Factory;
            }
        }

        private void DeleteKeyPressed(object sender, KeyEventArgs args)
        {
            if (args.Key.CompareTo(Key.Delete) == 0)
            {
                recordingController.Remove_Button_Click(null, null);
            }
        }

        /// <summary>
        /// Returns the embedded scroll object associated with the specified root element.
        /// </summary>
        private DependencyObject GetScrollChild(DependencyObject n)
        {
            bool terminate = false;
            object child = null;
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(n); i++)
            {
                child = VisualTreeHelper.GetChild(n, i);
                if (child is ScrollViewer)
                    return child as DependencyObject;
            }
            if (!terminate)
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(n); i++)
                    child =  GetScrollChild(VisualTreeHelper.GetChild(n, i));
            return child as DependencyObject;
        }
    }
}
